package views.loader
{
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	
	import gs.TweenLite;
	import gs.easing.Cubic;
	
	public class ImageLoaderView extends Sprite
	{
		public static const KEEP_RATE:int = 0;
		public static const EXTRA_FIT:int = 1;
		public static const NO_BORDER:int = 2;
		public static const NO_SCALE:int = 3;
		
		public static const TOP_LEFT:String = "top_left";
		public static const TOP_RIGHT:String = "top_right";
		public static const TOP_CENTER:String = "top_center";
		
		public static const MIDDLE_LEFT:String = "middle_left";
		public static const MIDDLE_RIGHT:String = "middle_right";
		public static const MIDDLE_CENTER:String = "middle_center";
		
		public static const BOTTOM_LEFT:String = "bottom_left";
		public static const BOTTOM_RIGHT:String = "bottom_right";
		public static const BOTTOM_CENTER:String = "bottom_center";
		
		
		private var imgContainer:Sprite;
		private var imgFrame:DisplayObject;
		private var loading:MovieClip;
		
		private var _imgURL:String;
		private var currentLoader:Loader;
		private var _clipToBounds:Boolean;
		private var clipMask:Shape;
		
		private const EASE_DURATION:Number = 0.5;
		
		public var keepLoaderShape:Boolean;
		public var easeIn:Boolean;
		public var align:String = "middle_center";
		public var scaleMode:int = 0;
		public var bitmap:Bitmap;
		public var delegate:I_ImageLoaderViewDelegate;
		
		public function ImageLoaderView(keepLoaderShape:Boolean = false)
		{
			this.keepLoaderShape = keepLoaderShape;
			initialize();
		}
		
		private function initialize():void
		{
			imgContainer = getChildByName("imgContainer") as Sprite;
			imgFrame = getChildByName("imgFrame");
			imgFrame.visible = false;
			
			loading = getChildByName("loading") as MovieClip;
			loading.visible = false;
			loading.stop();

			setSize(width,height);
		}
		
		private function setSize(w:Number,h:Number):void
		{
			if(!keepLoaderShape)
			{
				this.scaleX = 1;
				this.scaleY = 1;
				imgFrame.width = w;
				imgFrame.height = h;	
			}
			
			imgContainer.x = 0;
			imgContainer.y = 0;
			loading.x = imgFrame.width / 2;
			loading.y = imgFrame.height / 2;
		}
		
		private function scaleBitmap(image:DisplayObject):void
		{
			switch(scaleMode)
			{
				case EXTRA_FIT:
					image.width = imgFrame.width;
					image.height = imgFrame.height;
					break;
				
				case KEEP_RATE:
					var rateKeep:Number = Math.max(image.width/imgFrame.width,image.height/imgFrame.height);
					image.width = image.width / rateKeep;
					image.height = image.height / rateKeep;
					break;
				
				case NO_BORDER:
					var rateBoard:Number = Math.min(image.width/imgFrame.width,image.height/imgFrame.height);
					image.width = image.width / rateBoard;
					image.height = image.height / rateBoard;
					break;
				
				case NO_SCALE:
					default:
			}
			
		}
		
		private function layoutImage(image:DisplayObject):void
		{
			var hAlign:String = align.split("_")[1];
			var vAlign:String = align.split("_")[0];
			
			switch(hAlign)
			{
				case "left":
					image.x = 0;
					break;
				
				case "right":
					image.x = imgFrame.width - image.width;	
					break;
				
				case "center":
					image.x = (imgFrame.width - image.width) / 2;
					break;
			}
			
			switch(vAlign)
			{
				case "top":
					image.y = 0;
					break;
				
				case "middle":
					image.y = (imgFrame.height - image.height) / 2;	
					break;
				
				case "bottom":
					image.y = imgFrame.height - image.height;
					break;
			}
		}
		
		private function imageLoadedHandler(evt:Event):void
		{
			loading.visible = false;
			loading.stop();
			
			var loader:Loader = (evt.currentTarget as LoaderInfo).loader;
			try{
				bitmap = loader.content as Bitmap;
				bitmap.smoothing = true;
			}catch(err:Error){};
			
			scaleBitmap(loader);
			layoutImage(loader);
			
			if(easeIn)
			{
				loader.alpha = 0;
				imgContainer.addChild(loader);
				TweenLite.to(loader,EASE_DURATION,{alpha:1,ease:Cubic.easeInOut,onComplete:callDelegate});
				
			}else{
				
				imgContainer.addChild(loader);
				callDelegate();
			}
			
		}
		
		private function callDelegate():void
		{
			if(delegate is I_ImageLoaderViewDelegate)
				delegate.onImageLoaded(this);
		}
		
		private function onImageNotFound(evt:IOErrorEvent):void
		{
			loading.visible = false;
			loading.stop();
			trace(imgURL + "...IMAGE NOT FOUND!!!");
			callDelegate();
		}
		
		public function set imgURL(url:String):void
		{
			_imgURL = url;
			
			if(currentLoader is Loader)
			{
				currentLoader.unload();
				currentLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE,imageLoadedHandler);
			}
			
			while(imgContainer.numChildren > 0)
				imgContainer.removeChildAt(0);
			
			var loader:Loader = new Loader;
			currentLoader = loader;
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageLoadedHandler);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,onImageNotFound);
			loader.load(new URLRequest(imgURL),new LoaderContext(true));
			
			loading.visible = true;
			loading.play();
		}
		
		public function get imgURL():String
		{
			return _imgURL;	
		}
		
		public function set clipToBounds(clip:Boolean):void
		{
			if(clip == clipToBounds)
				return;
			_clipToBounds = clip;
			
			if(clipToBounds)
			{
				clipMask = new Shape;
				clipMask.graphics.beginFill(0xFF9900,.5);
				clipMask.graphics.drawRect(imgFrame.x,imgFrame.y,imgFrame.width,imgFrame.height);
				clipMask.graphics.endFill();
				
				imgContainer.mask = clipMask;
				addChild(clipMask);
				
			}else{
				removeChild(clipMask);
				imgContainer.mask = null;
			}
		}
		
		public function get clipToBounds():Boolean
		{
			return _clipToBounds;	
		}
	}
}